package com.xiaoshuidi.cloud.module.rooms.controller.admin.reservation;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.PdfWriter;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.excel.core.util.ExcelUtils;
import com.xiaoshuidi.cloud.module.finance.api.finance.FinanceMoneyFlowApi;
import com.xiaoshuidi.cloud.module.finance.api.finance.dto.FinanceMoneyFlowRespDTO;
import com.xiaoshuidi.cloud.module.rooms.controller.admin.reservation.vo.*;
import com.xiaoshuidi.cloud.module.rooms.convert.reservation.ReservationConvert;
import com.xiaoshuidi.cloud.module.rooms.enums.ApiConstants;
import com.xiaoshuidi.cloud.module.rooms.pojo.RoomReserveWithdrawalDetail;
import com.xiaoshuidi.cloud.module.rooms.service.IRoomHouseReserveService;
import com.xiaoshuidi.cloud.module.rooms.utils.PdfUtils;
import com.xiaoshuidi.cloud.module.rooms.vo.ExportBaseVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.io.IOException;
import java.util.List;


/**
 * 房源预定信息
 *
 * @author Feng
 * @since 2023-05-15
 */
@Tag(name = "管理后台 - 房源预定")
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping(ApiConstants.NAME + "/room-house-reserve")
public class RoomHouseReserveController {

    private final IRoomHouseReserveService reserveService;

    @Resource
    private FinanceMoneyFlowApi financeMoneyFlowApi;
    /**
     * 创建预定单
     *
     * @param req
     * @return
     */
    @PostMapping("/create")
    @Operation(summary = "创建预定单")
//    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:create')")
    public CommonResult<Long> create(@RequestBody @Valid ReserveCreateReq req) {
        return CommonResult.success(reserveService.create(req));
    }

    /**
     * 根据房源ID获取预定信息
     *
     * @param roomHouseId
     * @return
     */
    @GetMapping("/get-by-room-house")
    @Operation(summary = "根据房源ID获取预定信息")
    @Parameter(name = "roomHouseId", description = "房源id")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:query')")
    public CommonResult<ReserveGetResp> getByRoomHouseId(@RequestParam("roomHouseId") @NotNull(message = "房源ID不能为空") Long roomHouseId) {
        return CommonResult.success(reserveService.getByRoomId(roomHouseId));
    }

    /**
     * 根据房源ID获取预定历史 - 分页
     *
     * @param roomHouseId
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("/page-by-room-house")
    @Operation(summary = "根据房源ID获取预定历史 - 分页")
    @Parameters({
            @Parameter(name = "roomHouseId", description = "房源ID"),
            @Parameter(name = "pageNo", description = "页码"),
            @Parameter(name = "pageSize", description = "每页大小"),
    })
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:query')")
    public CommonResult<PageResult<ReserveGetResp>> page(@RequestParam("roomHouseId") @NotNull(message = "房源ID不能为空") Long roomHouseId,
                                                         @RequestParam("pageNo") @NotNull(message = "pageNo不能为空") Integer pageNo,
                                                         @RequestParam("pageSize") @NotNull(message = "pageSize不能为空") Integer pageSize) {
        return CommonResult.success(reserveService.page(roomHouseId, pageNo, pageSize));
    }


    /**
     * 支付成功回调
     *
     * @param req
     * @return
     */
    @PostMapping("/payment-successful")
    @Operation(summary = "支付成功回调")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:payment-successful')")
    public CommonResult<Boolean> paymentSuccessful(@Valid @RequestBody PaymentSuccessfulReq req) {
        return CommonResult.success(reserveService.paymentSuccessful(req.getReserveId(), req.getPaymentId(), req.getPayTime(),null));
    }

    /**
     * 预定取消
     *
     * @param reserveId
     * @return
     */
    @PostMapping("/cancel")
    @Operation(summary = "预定取消")
    @Parameter(name = "reserveId", description = "预定id")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:cancel')")
    public CommonResult<Boolean> cancel(@RequestParam("reserveId") @NotNull(message = "预定ID不可为空") Long reserveId) {
        return CommonResult.success(reserveService.cancel(reserveId, null));
    }

    /**
     * 预定编辑
     *
     * @param req
     * @return
     */
    @PostMapping("/update")
    @Operation(summary = "预定编辑")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:update')")
    public CommonResult<Boolean> update(@Valid @RequestBody ReserveUpdateReq req) {
        return CommonResult.success(reserveService.update(req));
    }

    /**
     * 预定账单列表
     *
     * @param req
     * @return
     */
    @GetMapping("/bill-page")
    @Operation(summary = "预定账单列表")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:bill-page')")
    public CommonResult<PageResult<ReserveBillPageResp>> billPage(ReserveBillPageReq req) {
        return CommonResult.success(reserveService.billPage(req));
    }

    /**
     * 根据房源ID获取预定信息
     *
     * @param id
     * @return
     */
    @GetMapping("/get")
    @Operation(summary = "根据房源ID获取预定信息")
    @Parameter(name = "id", description = "房源id")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:query')")
    public CommonResult<ReserveGetResp> get(@RequestParam("id") @NotNull(message = "ID不能为空") Long id) {
        return CommonResult.success(reserveService.get(id));
    }

    /**
     * 预定账单导出
     *
     * @param req
     * @return
     */
    @PostMapping("/bill-export")
    @Operation(summary = "预定账单导出")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:bill-export')")
    public CommonResult<ExportBaseVo> billExport(@RequestBody ReserveBillPageReq req) {
        return CommonResult.success(reserveService.billExport(req));
    }

    /**
     * 预定单导出
     *
     * @param req
     * @return
     */
    @PostMapping("/reserve-export")
    @Operation(summary = "预定单导出")
    public CommonResult<ExportBaseVo> reserveExport(@RequestBody ReserveBillPageReq req) {
        return CommonResult.success(reserveService.reserveExport(req));
    }

    /**
     * 根据用户ID获取预定信息
     *
     * @param userId 用户id
     * @return
     */
    @GetMapping("/get-by-user")
    @Operation(summary = "根据用户ID获取预定信息")
    @Parameter(name = "userId", description = "用户id")
    @PreAuthorize("@ss.hasAnyPermissions('rooms:reserve:query')")
    public CommonResult<PageResult<GetByUserIdRespVO>> getByUserId(@RequestParam("userId") @NotNull(message = "用户id不能为空") Long userId,
                                                                   @RequestParam("pageNo") @NotNull(message = "pageNo不能为空") Integer pageNo,
                                                                   @RequestParam("pageSize") @NotNull(message = "pageSize不能为空") Integer pageSize) {
        return CommonResult.success(reserveService.getByUserId(userId, pageNo, pageSize));
    }

    @GetMapping("/template-download")
    @Operation(summary = "预定账单模版导出")
    public CommonResult<RoomReserveExportResp> templateDownload(@RequestParam Long apartmentId){
        RoomReserveExportResp roomReserveExportResp = reserveService.templateDownload(apartmentId);
        return CommonResult.success(roomReserveExportResp);
    }

    @PostMapping("reserve-import")
    public CommonResult<String> readingOrderImport(@Parameter String fileUrl) {
        CommonResult<String> result = reserveService.reserveImport(fileUrl);
        return result;
    }

    @GetMapping("/withdraw/detail")
    @Operation(summary = "预定账单退定明细")
    public CommonResult<List<RoomReserveWithdrawalDetail>> withdrawDetail(@RequestParam("reserveId") @NotNull(message = "预定单ID不能为空") Long reserveId,
                                                                          @RequestParam("reasonId") @NotNull(message = "退定原因不能为空") Integer reasonId){
        return CommonResult.success(reserveService.getWithdrawDetail(reserveId, reasonId));
    }

    @GetMapping("/withdraw")
    @Operation(summary = "预定账单退定")
    public CommonResult withdrawReserve(@RequestParam("reserveId") @NotNull(message = "预定单ID不能为空") Long reserveId,
                                        @RequestParam("reasonId") @NotNull(message = "退定原因不能为空") Integer reasonId){
        reserveService.reserveWithdraw(reserveId,reasonId);
        return CommonResult.success();
    }

    @PostMapping("/withdraw/pay")
    @Operation(summary = "退定账单付款")
    public CommonResult withdrawPay(@Valid @RequestBody ReserveWithdrawPayReq payReq) {
        reserveService.withdrawPay(payReq);
        return CommonResult.success();
    }

    /**
     * 退定账单列表
     *
     * @param req
     * @return
     */
    @GetMapping("/withdraw/bill-page")
    @Operation(summary = "退定账单列表")
    public CommonResult<PageResult<ReserveBillPageResp>> withdrawBillPage(ReserveBillPageReq req) {
        return CommonResult.success(reserveService.withdrawBillPage(req));
    }


    @GetMapping("/withdraw/detailById")
    @Operation(summary = "预定账单退定明细")
    public CommonResult<List<RoomReserveWithdrawalDetail>> withdrawDetailById(@RequestParam("reserveId") @NotNull(message = "预定单ID不能为空") Long reserveId){
        return CommonResult.success(reserveService.getWithdrawDetailById(reserveId));
    }

    @GetMapping("/withdraw/bill-export")
    @Operation(summary = "导出退定账单")
    public void exportWithdrawBill(@ModelAttribute ReserveBillPageReq req, HttpServletResponse response) throws IOException {
        req.setPageSize(100);
        // 导出 Excel
        PageResult<ReserveBillPageResp> pageResult = reserveService.withdrawBillPage(req);
        ExcelUtils.write(response,"退定账单.xlsx", "数据", ReserveWithdrawExcelVO.class, pageResult,
                ReservationConvert.INSTANCE::convertBeanList2ExcelVOList, pageNo ->{
                    req.setPageNo(pageNo);
                    return reserveService.withdrawBillPage(req);
                });
    }



    /**
     * 预定账单PDF
     * @param reserveId
     * @param sourceBizId
     * @param sourceBizType
     * @param response
     * @throws Exception
     */
    @GetMapping("/pdf")
    public void pdf(@RequestParam("reserveId") Long reserveId,
                    @RequestParam(value = "sourceBizId", required = false) String sourceBizId,
                    @RequestParam(value = "sourceBizType", required = false) String sourceBizType,
                    @RequestParam(value = "billPrint", required = false) String billPrint,
                    HttpServletResponse response) throws Exception {
        //查询预定记录
        ReserveGetResp reserveGetResp = reserveService.get(reserveId);
        //查询流水
        CommonResult<FinanceMoneyFlowRespDTO> app = financeMoneyFlowApi.getApp(null, sourceBizId, sourceBizType);

        Font header = PdfUtils.getFont();
        header.setSize(18);
        header.setStyle(Font.FontStyle.BOLD.getValue());
        Font bold = PdfUtils.getFont();
        bold.setStyle(Font.FontStyle.BOLD.getValue());

        PdfUtils.PdfDoc doc = PdfUtils.newPdfDoc();
        OutputStream os = response.getOutputStream();

        if (reserveGetResp == null || !app.isSuccess() || app.getData() == null) {
            doc.addParagraph("未找到结算信息");
            doc.close();
            os.close();
            return;
        }
        FinanceMoneyFlowRespDTO financeMoneyFlowRespDTO = app.getData();

        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(String.format("预定账单_%s.pdf", DateUtil.format(new Date(), "yyyyMMddHHmmss")), "UTF-8"));
        response.setContentType("application/pdf;charset=UTF-8");

        PdfWriter.getInstance(doc.getDoc(), os);
        doc.open();

        doc.addParagraph(DateUtil.format(new Date(), "yyyy/MM/dd"));
        doc.addTable(4, tb -> {
                    // 主表单信息
                    tb.addCell("预定账单", 4, header, cell -> {
                        cell.setPaddingTop(5);
                        cell.setPaddingBottom(10);
                    })
                            .addCell("业务信息", 4, bold, Element.ALIGN_LEFT)
                            .addCell("账单编号").addCell(reserveGetResp.getBillNo(), 3)
                            .addCell("入住日期", reserveGetResp.getCheckInDate(), "退房日期",
                                    reserveGetResp.getCheckOutDate())
                            .addCell("业务门店", financeMoneyFlowRespDTO.getApartmentName(), "业务管家", reserveGetResp.getSalesperson())
                            .addCell("房屋位置").addCell(financeMoneyFlowRespDTO.getRoomName(), 3)
                            .addCell("租户名称", reserveGetResp.getBooker(), "租户电话", reserveGetResp.getBookerPhone())
                            .addCell("付款账户类型", reserveGetResp.getCustomType().equals("1")
                                    ? "个人" : "企业", "预定状态", reserveGetResp.getStatusStr())
                            .addCell("支付方式", financeMoneyFlowRespDTO.getPayMethod(), "支付类型", financeMoneyFlowRespDTO.getFeeType())
                            .addCell("交易流水号").addCell(financeMoneyFlowRespDTO.getTradeNo(), 3)
                            .addCell("附件").addCell(StrUtil.isEmpty(financeMoneyFlowRespDTO.getRoomRentOrderNo())?"1、房屋预定确认单；":"1、房屋预定确认单；2、合同编号："+financeMoneyFlowRespDTO.getRoomRentOrderNo() , 3);
                    // 账单信息
                    tb.addCell("账单信息", 4, bold, Element.ALIGN_LEFT)
                            .addCell("费用名称", "费用金额", "费用备注", "创建时间");

                    tb.addCell(financeMoneyFlowRespDTO.getFeeType(), financeMoneyFlowRespDTO.getTradeAmount().toString(), "",
                            DateUtil.format(financeMoneyFlowRespDTO.getTradeTime(), "yyyy/MM/dd HH:mm:ss"));
                    tb.addCell("总计").addCell(financeMoneyFlowRespDTO.getTradeAmount() + "元", 3);
                    //备注打印
                    tb.addCell(String.format("备注 : %s", StrUtil.isNotBlank(reserveGetResp.getRemark()) ? reserveGetResp.getRemark() : "")
                            , 4, Element.ALIGN_LEFT);
                    tb.options(t -> {
                        t.setWidthPercentage(100);
                        try {
                            t.setWidths(new float[]{18f, 32f, 18f, 32f});
                        } catch (DocumentException ignore) {
                        }
                    });
                }
        );

        //查看是否二联
        if (billPrint.equals("2")) {
            doc.addParagraph(DateUtil.format(new Date(), "yyyy/MM/dd"));
            doc.addTable(4, tb -> {
                        // 主表单信息
                        tb.addCell("预定账单", 4, header, cell -> {
                            cell.setPaddingTop(5);
                            cell.setPaddingBottom(10);
                        })
                                .addCell("业务信息", 4, bold, Element.ALIGN_LEFT)
                                .addCell("账单编号").addCell(reserveGetResp.getBillNo(), 3)
                                .addCell("入住日期", reserveGetResp.getCheckInDate(), "退房日期",
                                        reserveGetResp.getCheckOutDate())
                                .addCell("业务门店", financeMoneyFlowRespDTO.getApartmentName(), "业务管家", reserveGetResp.getSalesperson())
                                .addCell("房屋位置").addCell(financeMoneyFlowRespDTO.getRoomName(), 3)
                                .addCell("承租人", financeMoneyFlowRespDTO.getRenter(), "经办人", financeMoneyFlowRespDTO.getOperator())
                                .addCell("收款账户", "公司", "预定状态", reserveGetResp.getStatusStr())
                                .addCell("支付方式", financeMoneyFlowRespDTO.getPayMethod(), "收款类型", financeMoneyFlowRespDTO.getFeeType())
                                .addCell("交易流水号").addCell(financeMoneyFlowRespDTO.getTradeNo(), 3)
                                .addCell("附件").addCell(StrUtil.isEmpty(financeMoneyFlowRespDTO.getRoomRentOrderNo())?"1、房屋预定确认单；":"1、房屋预定确认单；2、合同编号："+financeMoneyFlowRespDTO.getRoomRentOrderNo() , 3);
                        // 账单信息
                        tb.addCell("账单信息", 4, bold, Element.ALIGN_LEFT)
                                .addCell("费用名称", "费用金额", "费用备注", "创建时间");

                        tb.addCell(financeMoneyFlowRespDTO.getFeeType(), financeMoneyFlowRespDTO.getTradeAmount().toString(), "",
                                DateUtil.format(financeMoneyFlowRespDTO.getTradeTime(), "yyyy/MM/dd HH:mm:ss"));
                        tb.addCell("总计").addCell(financeMoneyFlowRespDTO.getTradeAmount() + "元", 3);
                        //备注打印
                        tb.addCell(String.format("备注 : %s", StrUtil.isNotBlank(reserveGetResp.getRemark()) ? reserveGetResp.getRemark() : "")
                                , 4, Element.ALIGN_LEFT);
                        tb.options(t -> {
                            t.setWidthPercentage(100);
                            try {
                                t.setWidths(new float[]{18f, 32f, 18f, 32f});
                            } catch (DocumentException ignore) {
                            }
                        });
                    }
            );
        }
        doc.getDoc().newPage();
        doc.close();
        os.close();
    }

}
